﻿using Framework.LogServices.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Framework.LogServices
{
    /// <summary>
    /// 日志服务
    /// </summary>
    public class LoggingServices: ILoggingServices
    {
        #region -- 静态全局通用类
        /// <summary>
        /// 日志队列
        /// </summary>
        static ConcurrentQueue<LogEntity> _logQueue= new ConcurrentQueue<LogEntity>();

        /// <summary>
        /// 用于通知后台任务停止的信号
        /// </summary>
        private static readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();

        /// <summary>
        /// 后台处理任务
        /// </summary>
        private static Task _backgroundTask;

        /// <summary>
        /// 日志记录委托
        /// </summary>
        private static Func<List<LogEntity>,Task> _loggingDelegation;

        private HashSet<LogEntity> _errorLog = new HashSet<LogEntity>();

        /// <summary>
        /// 批次处理数量
        /// </summary>
        const int _logBatchNum = 1000;

        /// <summary>
        /// 当队列为空时的等待延迟（毫秒）
        /// </summary>
        const int emptyQueueDelay = 1000;
        #endregion

        /// <summary>
        /// 日志服务
        /// </summary>
        /// <param name="func">日志记录委托</param>
        public LoggingServices(Func<List<LogEntity>, Task> loggingDelegation)
        {
            _loggingDelegation = loggingDelegation;
            //启动后台任务
            _backgroundTask = Task.Factory.StartNew(() => BackgroundService(_cancellationTokenSource.Token).ConfigureAwait(false), TaskCreationOptions.LongRunning);
        }

        /// <summary>
        /// 日志记录后台任务
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task BackgroundService(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                List<LogEntity> logEntries = [];
                while(logEntries.Count< _logBatchNum && _logQueue.TryDequeue(out LogEntity? logEntry))
                {
                    if (logEntry != null) logEntries.Add(logEntry);
                }

                if (logEntries.Count>0)
                {
                    try
                    {
                        //执行日志记录委托
                        await _loggingDelegation(logEntries);
                    }
                    catch(Exception e)
                    {
                        logEntries.ForEach(x =>
                        {
                            if (!_errorLog.Contains(x))
                            {
                                _logQueue.Append(x);
                                _errorLog.Add(x);
                            }
                        });
                        Console.WriteLine($"{DateTime.Now}--> 记录日志时出现未知异常，共有：{_errorLog.Count}条异常日志信息，即将重新记录，异常信息：{e.Message}，异常明细：{e}");
                    }
                }
                else
                {
                    _errorLog.Clear();
                    //无日志记录，挂起指定毫秒数
                    await Task.Delay(emptyQueueDelay, token);
                }
            }
        }

        public void WriteErrorLog(string logGroup, string logTitle, string logMsg, Exception ex = null)
        {
            _logQueue.Append(new LogEntity() { Group = logGroup, Message = logMsg, Title = logTitle, Leve = "Error", Exception = ex, Timestamp = DateTime.Now });
        }

        public void WriteInfoLog(string logGroup, string logTitle, string logMsg)
        {
            _logQueue.Append(new LogEntity() { Group = logGroup, Message = logMsg, Title = logTitle, Leve = "Info", Timestamp = DateTime.Now });
        }

        public void WriteLog(string logGroup, string logTitle, string logLeve, string logMsg, Exception ex = null)
        {
            _logQueue.Append(new LogEntity() { Group = logGroup, Message = logMsg, Title = logTitle, Leve = logLeve, Exception = ex, Timestamp = DateTime.Now });
        }

        public void WriteWarraingLog(string logGroup, string logTitle, string logMsg)
        {
            _logQueue.Append(new LogEntity() { Group = logGroup, Message = logMsg, Title = logTitle, Leve = "Warraing", Timestamp = DateTime.Now });
        }
    }
}
